﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Diagnostics;
using System.Collections;
using SuraQR.Config;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using SuraQR.Bean;
using System.Windows.Forms;

namespace SuraQR.Controller
{
    class QRCodeEngineService
    {
        private string _comPortName = "COM5";
        private bool isStart = false;
        private SerialPort mySerialPort = null;
        private IQRCodeEngineService _iEvent;
        private ArrayList _qrTmpData;
        private string _currentID = "";
        private int _currentMaxSize = 0;
        private Dictionary<int, String> _partOfQRData;
        private bool[] statReader;
        private bool _pause = false;

        public QRCodeEngineService()
        {
            _qrTmpData = new ArrayList();
            _partOfQRData = new Dictionary<int, String>();
            statReader = new bool[10];


        }
        public void strat(string _comPort,IQRCodeEngineService ievent)
        {
            try
            {
                _comPortName = _comPort;
                _iEvent = ievent;

                mySerialPort = new SerialPort(_comPortName); 
                mySerialPort.BaudRate = 9600;
                mySerialPort.Parity = Parity.None;
                mySerialPort.StopBits = StopBits.One;
                mySerialPort.DataBits = 8;
                mySerialPort.Handshake = Handshake.None;

               
                mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
                mySerialPort.Open();
                Debug.WriteLine("Start Port : " + _comPortName);
                isStart = true;
            }
            catch (Exception e)
            {
                Debug.Write(e);
                isStart = false;
                ievent.onError(e);
                MessageBox.Show("COM PORT ERROR : " + e.ToString ());
            }
        }

        private String tmp = "";
        private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                SerialPort sp = (SerialPort)sender;
                string indata = sp.ReadExisting();

                Debug.WriteLine("Data Received :" + indata);
                if (indata.IndexOf("\r\n") == -1)
                {
                    _pause = true;
                    tmp += indata;
                }
                else if(tmp != "")
                {
                    indata = tmp + indata;
                    _pause = false;
                }

                if (_pause == false)
                {
                    tmp = "";
                    this.readDataQR(indata);
                    
                }                                             
            }
            catch (Exception ex)
            {
                Debug.WriteLine("DataReceivedHandler : " + ex);
                if (this.IsStart)
                {
                   // this.close();
                }
            }

        }

        public void clearReadData()
        {
            _qrTmpData.Clear();
            _currentID = "";
            _currentMaxSize = 0;
            _partOfQRData.Clear();
            statReader = new bool[10];
            _iEvent.onClear();
        }

        private void readDataQR(String rawData)
        {
            //Debug.WriteLine(" in form : " + rawData);


            // check length
            if (rawData.Length < 20)
            {
                Debug.WriteLine("error size");
                msg("Error size");
                return;
            }
            //check header data
            string h = rawData.Substring(0, PropertiesConfig._Header.Length);
            if (!PropertiesConfig._Header.Equals(h))
            {
                Debug.WriteLine("not SR QR");
                msg("QR not for this application");
            }

            //SR1200#1.110#7:7#9d7cf70e-7842-4155-9769-a198d6fba5bc#
            //version
            string[] str = rawData.Split('#');
            if (!PropertiesConfig._AppVersin.Equals(str[1]))
            {
                Debug.WriteLine("version not math");
                msg("version not math");
            }

            // push data
            //first
            if (_qrTmpData.Count == 0)
            {
                _currentID = str[3];
                _currentMaxSize = Convert.ToInt32(str[2].Split(':')[1]);
                _iEvent.onFirst(_currentMaxSize);
            }
            // exist
            if (_qrTmpData.Count > 0)
            {
                // check same uid
                if (!_currentID.Equals(str[3]))
                {
                    Debug.WriteLine("Not same UUID QRCODE");
                    msg("not same QR part ID");
                    return;
                }

            }

            // insert DATA
            string currentStr = rawData;
            int currentIndex = Convert.ToInt32(str[2].Split(':')[0]);
            Debug.WriteLine("Current INDEX : " + currentIndex);

            bool isExist = _qrTmpData.Contains(currentStr);

            if (isExist)
            {
                Debug.WriteLine("Duplicate index : " + currentIndex);
                msg("scan duplicate");
            }
            else
            {
                _qrTmpData.Add(currentStr);
                _partOfQRData.Add(currentIndex, currentStr);
                //Debug.WriteLine("Insert index : " + currentIndex);
                statReader[currentIndex - 1] = true;
                Debug.WriteLine("part " + currentIndex + "  => complete");

                //status
                string s = "";
                for (int i = 0; i < _currentMaxSize; i++)
                {
                    s += "[" + (i + 1) + "=" + statReader[i] + "]  ";
                }

                Debug.WriteLine(s);
                _iEvent.onReadComplate(currentIndex,_qrTmpData.Count, s);
            }

            Debug.WriteLine(" > " + _qrTmpData.Count + " : " + _currentMaxSize);
            if (_qrTmpData.Count == _currentMaxSize)
            {
                Debug.WriteLine("Scan is finish");
                //msg("complete");
                this.onfinish();
            }


        }
        private void onfinish()
        {
            try
            {
                //make string
                StringBuilder b = new StringBuilder();
                for (int i = 1; i <= _currentMaxSize; i++)
                {
                    b.Append(_partOfQRData[i].Split('#')[4]);
                }

                //
                string base64 = b.ToString();
                Debug.WriteLine("bsize : " + base64.Length);
                // base64
                byte[] b64 = Convert.FromBase64String(base64);
                Debug.WriteLine("Zip byte Base64 : " + b64.Length);
                byte[] upzip = SRUtils.Unzip(b64);
                Debug.WriteLine("Unzip byte Base64 : " + upzip.Length);

                Stream stream = new MemoryStream(upzip);
                BinaryFormatter formatter = new BinaryFormatter();
                SOROR12011 outPutData = (SOROR12011)formatter.Deserialize(stream);
                stream.Close();

                // call Event
                _pause = true;
                _iEvent.onComplete(outPutData);
                _pause = false;
            }
            catch (FormatException e)
            {
                Debug.WriteLine("Read QR Error");
                Debug.WriteLine(e);
            }
        }

        private void msg(string msg)
        {
            Debug.WriteLine(msg);
            _iEvent.onError(new Exception(msg));
        }
        public void close()
        {
            if (IsStart)
            {
                mySerialPort.Close();
                isStart = false;
                Debug.WriteLine("Close.................");
            }
        }
        public bool IsStart
        {
            get { return isStart; }
        }
        public string ComPortName
        {
            get { return _comPortName; }            
        }
        public void pause()
        {
            _pause = true;
        }
        public void unpause()
        {
            _pause = false;
        }
        public string[] getCOMPortList()
        {
            string[] c = SerialPort.GetPortNames();

            for (int i = 0; i < c.Length; i++)
            {
                Debug.WriteLine(": " + c[i]);
            }

            return c;
        }
    }
}
